﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Psm.Protocol;
using Psm.Transport;
using Psm.Container;
using Psm.Messaging;
using Psm.Session;
using Psm.Util;

namespace Psm.Core
{
    public class PsmSession : ISession
    {
        private PsmHost host;
        private IClientTransport clientTransport;
        private IProtocol protocol;
        private IProcessor processor;
        private IMessageFactory messageFactory;
        public event EventHandler<SessionClosedEventArgs> SessionClosed;
        private IDictionary<string, object> state = new Dictionary<string, object>();

        internal void StartProcessing()
        {
            this.protocol.StartProcessing();
            this.processor.NewSession(this);
        }

        public PsmSession(PsmHost host, IClientTransport clientTransport)
        {   
            this.host = host;
            this.clientTransport = clientTransport;
            this.protocol = Repository.GetInstance<IProtocol>(host.Configuration.Protocol.Type, host.Configuration.Protocol.Composition);
            this.processor = Repository.GetInstance<IProcessor>(host.Configuration.Processor.Type, host.Configuration.Processor.Composition);
            this.processor.Intialize();
            this.messageFactory = Repository.GetInstance<IMessageFactory>(host.Configuration.Messaging.Type, host.Configuration.Messaging.Composition);
            this.protocol.NewMessage += new EventHandler<NewMessageEventArgs>(NewMessageHandler);
            this.protocol.ProtocolShutdown += new EventHandler<ProtocolShutdownEventArgs>((o, e) => OnSessionClosed());
            this.protocol.InitializeProtocol(this.clientTransport, messageFactory);
        }

        private void OnSessionClosed()
        {
            this.processor.SessionClosed(this);
            EventHandler<SessionClosedEventArgs> handler = this.SessionClosed;
            if (handler != null)
                handler(this, new SessionClosedEventArgs());
        }

        private void NewMessageHandler(object sender, NewMessageEventArgs args)
        {
            this.processor.ProcessMessage(this, args.Message);
        }

        public IMessage CreateMessage(ByteBuffer payload)
        {
            return messageFactory.CreateMessage(payload);
        }

        public void SendMessage(IMessage message)
        {
            this.protocol.SendMessage(message);
        }

        public IDictionary<string, object> State
        {
            get { return state; }
        }

        public void Flush()
        {
            this.protocol.Flush();
        }
    }
}
